﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace TurtlePop
{
    public class Board
    {
        private Stack<List<List<BoardCellState>>> undoStack = new Stack<List<List<BoardCellState>>>();
        private BoardColumn[] columns;
        public BoardColumn this[int index]
        {
            get
            {
                if (index < 0) return null;
                if (index >= columns.Length) return null;
                return columns[index];
            }
        }
        public int Columns
        {
            get
            {
                return columns.Length;
            }
        }
        public int Rows
        {
            get
            {
                return this[0].Rows;
            }
        }
        public Board(int theColumns, int theRows)
        {
            columns = new BoardColumn[theColumns];
            for (int column = 0; column < theColumns; ++column)
            {
                columns[column] = new BoardColumn(theRows);
            }
            for (int column = 0; column < Columns; ++column)
            {
                for (int row = 0; row < Rows; ++row)
                {
                    for (int direction = Directions.First; direction <= Directions.Last; ++direction)
                    {
                        int nextColumn = column + Directions.DeltaX[direction];
                        int nextRow = row + Directions.DeltaY[direction];
                        this[column][row].Neighbors[direction] = (this[nextColumn] != null) ? (this[nextColumn][nextRow]) : (null);
                    }
                }
            }
        }
        public void MarkRegions()
        {
            ClearRegions();
            int region = 0;
            for (int column = 0; column < Columns; ++column)
            {
                for (int row = 0; row < Rows; ++row)
                {
                    if (this[column][row].Region == -1)
                    {
                        this[column][row].PaintRegion(region);
                        region++;
                    }
                }
            }
        }
        public void ClearStates()
        {
            foreach (BoardColumn column in columns)
            {
                column.ClearStates();
            }
        }
        public void ClearRegions()
        {
            foreach (BoardColumn column in columns)
            {
                column.ClearRegions();
            }
        }
        public void Clear()
        {
            foreach (BoardColumn column in columns)
            {
                column.Clear();
            }
            undoStack.Clear();
        }
        public void CleanUpBoard()
        {
            for (int column = 0; column < Columns; ++column)
            {
                for (int row = 0; row < Rows; ++row)
                {
                    while (this[column][row].State == BoardCellState.Remove)
                    {
                        this[column][row].CollapseDown();
                    }
                }
            }
            for (int column = 0; column < Columns; ++column)
            {
                if (this[column][Rows - 1].State != BoardCellState.Empty)
                {
                    if (this[column][Rows - 1].Neighbors[Directions.East] != null)
                    {
                        if (this[column][Rows - 1].Neighbors[Directions.East].State == BoardCellState.Empty)
                        {
                            this[column][Rows - 1].Neighbors[Directions.East].CollapseRight(true);
                        }
                    }
                }
            }
            MarkRegions();
        }
        private void pushState()
        {
            List<List<BoardCellState>> boardState = new List<List<BoardCellState>>();
            for (int column = 0; column < Columns; ++column)
            {
                List<BoardCellState> columnState = new List<BoardCellState>();
                for (int row = 0; row < Rows; ++row)
                {
                    columnState.Add(this[column][row].State);
                }
                boardState.Add(columnState);
            }
            undoStack.Push(boardState);
        }
        public int MakeMove(int theColumn, int theRow)
        {
            if (this[theColumn][theRow].State == BoardCellState.Empty) return 0;
            if (this[theColumn][theRow].Isolated) return 0;
            int result = 0;
            pushState();
            int region = this[theColumn][theRow].Region;
            for (int column = 0; column < Columns; ++column)
            {
                for (int row = 0; row < Rows; ++row)
                {
                    if (this[column][row].Region == region)
                    {
                        result++;
                        this[column][row].State = BoardCellState.Remove;
                    }
                }
            }
            return result;
        }
        public int MovesLeft
        {
            get
            {
                int result = 0;
                HashSet<int> regions = new HashSet<int>();
                for (int column = 0; column < Columns; ++column)
                {
                    for (int row = 0; row < Rows; ++row)
                    {
                        if (this[column][row].State != BoardCellState.Empty && !this[column][row].Isolated)
                        {
                            if(!regions.Contains(this[column][row].Region))
                            {
                                result++;
                                regions.Add(this[column][row].Region);
                            }
                        }
                    }
                }
                return result;
            }
        }
        public int MovesMade
        {
            get
            {
                return undoStack.Count;
            }
        }
    }
}
